package com.hfi.security.app.server;

import com.hfi.security.core.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

/**
 * @author ChangLiang
 * @date 2019/9/3
 */
@Configuration
public class TokenStoreConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    @ConditionalOnProperty(prefix = "hfi.security.oauth2", name = "storeType", havingValue = "redis")
    public TokenStore redisTokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }

    /**
     * 为什么写成静态内部类的方式？
     * 声明了两个TokenStore 那不就是会冲突了 使用ConditionalOnProperty
     */
    @Configuration
    @ConditionalOnProperty(prefix = "hfi.security.oauth2", name = "storeType", havingValue = "jwt", matchIfMissing =
            true)
    public static class JwtTokenConfig{

        @Autowired
        private SecurityProperties securityProperties;

        @Autowired
        private UserDetailsService hfiUserDetailsService;

        @Bean
        public TokenStore jwtTokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }

        /**
         * 处理token生成中的处理
         * @return
         */
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
            // 密签的签名 不同的第三方应用signingKey应该是不同的
            // 发令牌的时候用signingKey来签名 第三方client也使用这个signingKey来验签
            // 如果你这个SigningKey暴露了 其他人也可以用这个SigningKey来签发令牌 就可以随意进行你的系统了
            jwtAccessTokenConverter.setSigningKey(securityProperties.getOauth2().getJwtSigningKey());
            jwtAccessTokenConverter.setAccessTokenConverter(defaultAccessTokenConverter());
            return jwtAccessTokenConverter;
        }

        @Bean
        public DefaultAccessTokenConverter defaultAccessTokenConverter() {
            DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter();
            defaultAccessTokenConverter.setUserTokenConverter(defaultUserAuthenticationConverter());
            return defaultAccessTokenConverter;
        }

        @Bean
        public DefaultUserAuthenticationConverter defaultUserAuthenticationConverter() {
            DefaultUserAuthenticationConverter defaultUserAuthenticationConverter =
                    new DefaultUserAuthenticationConverter();
            // 设置userDetailService 从中取出用户信息
            defaultUserAuthenticationConverter.setUserDetailsService(hfiUserDetailsService);
            return defaultUserAuthenticationConverter;
        }

        /**
         * 向jwt令牌中添加信息 每个jpaDemo可能是不同的
         * 业务系统可以加入jwtTokenEnhancer bean 来覆盖掉默认的逻辑
         * @return
         */
        @Bean
        @ConditionalOnMissingBean(name="jwtTokenEnhancer")
        public TokenEnhancer jwtTokenEnhancer() {
            return new HfiJwtTokenEnhancer();
        }
    }
}
